58同城作为中国最大的分类信息网站,向用户提供房源、工作、二手车和黄页等多种生活信息,如何给用户带来更好的体验,如何在现有流量的基础上获取更高的收益,在业务逻辑、算法策略、页面UI布局等环节可以通过A/B测试实验,根据实验的结果做出合理的选择。为了58各业务线可以便捷、灵活、高效的开展A/B测试实验,我们打造了58通用ABTest实验平台"日晷"。日晷,是适用于58各个业务线的通用A/B测试实验平台,产品、技术和决策者可以针对现有流量建立AB版本实验,对现有产品、特性进行版本迭代,通过各个版本间的线上实验数据做出更优的选择,推动业务持续增长。
什么是A/B测试
A/B测试是从两个或多个产品的优化方案中选出最优方案的方法。A/B测试是对比试验,对随机抽样的小流量用户样本进行总体的预估。我们在试验前会对试验的结果进行预估,通过对比原始版本和试验版本的样本数据,从而对两个版本的差异进行判断。
58APP客户端中的二手车猜你喜欢的展示界面,双排帖子展示和单排帖子展示,哪个用户的体验更好,能带来更多的点击和转化。可以将双排帖子展示作为A基准实验,将单排帖子展示作为B对照实验,分别将小流量分配到两个实验上,根据实验数据对比,来决定用哪个实验来展示效果更优。
怎么进行A/B测试
A/B测试的试验过程是,在同一时间段,给两组用户(对照组和实验组)分别展示优化前(对照组)和优化后(实验组)的结果,并通过数据统计分析,判断优化前后的多个评估指标是否符合预期,再决定是否发布新的版本。
日晷ABTest的实验流程如下图所示,用户请求ABTest服务,ABTest服务将该请求分流到实验的A策略或者B策略上。同时,用户的浏览行为会产生埋点日志,根据日志统计出的数据效果,得到一段时间范围内,数据效果更好的版本,并将实验的分流比例重新配置。
日晷核心功能介绍
日晷支持单层或者多层的A/B测试实验,流量在实验之间,或者实验层之间都是正交的。用户可以通过WEB系统界面进行实验配置,以及查看实时和历史数据统计效果进行实验版本的对比。日晷的分流是足够散列均匀的,保证分流的科学有效。日晷使用Druid实时OLAP引擎进行多维度、多层次的日志数据统计分析。
日晷有以下几个方面的特性:
低成本:界面友好,简单易用,通过简单的操作设置或者接口调用即可达成实验分流的目的
实验灵活:A/B实验既有单层实验,也有多层实验,业务方自主选择合适的实验类型,进行合理的流量和算法策略的分配
分流科学:这是A/B测试的基础,日晷实验的流量是随机均匀的。不同实验和实验的各层间是正交独立的
数据驱动:用数据说话,用数据来支撑哪个版本的实验效果更好,包含实时和历史数据的多维度分析
在这里我们先从低成本、灵活实验上介绍日晷实验平台,对于分流科学和数据驱动我们在实验平台架构一节中详细介绍。
日晷的实验的操作流程是简单、易操作的,仅需简单几步:
新建实验->进入实验->输入实验名称、选择实验层、输入算法号、配置分流比例、选择实验是否运行->保存,实验即可生效。分流比例的修改,或者实验的上下线,也仅仅需要修改“分流比例”,和选择“是否运行”。
为了实验的安全和隐私,提供了授权账号和实验是否公开的选择,用户可以将实验只开放给指定账号的用户。仅在实验指定账号范围内的用户才可以修改实验的配置。
日晷的单层实验
日晷的单层实验,是为了满足实验流量100%独占的需求,一个请求仅命中一个实验。
单层实验的应用场景,比如产品UI迭代、业务特性迭代、产品功能更新等。典型的例子,在列表页验证添加“放心车”标识前后,对于用户转化的影响,由于是单一场景下,独占流量的实验对比,即可用单层实验。
在日晷实验平台建立单层实验,只需输入实验名称,在实验内建立A/B版本的实验分流配比,如图所示二手车入口提示单层实验:
日晷的多层实验
日晷的多层实验,是为了满足只在一个实验下,但是需要对实验不同层次、类别配置不同的参数的需求,多层实验将流量复制多份,一个用户请求在此实验内的各层都分别命中一次。
多层实验的应用场景,比如产品结构上是分层的,系统功能上是依赖层次性的结果。典型的例子,如下图所示的推荐系统流程,推荐系统需要从海量数据中经过召回、排序、规则、展示等层次,最后获取到topN的推荐结果。关于推荐系统和推荐各层的功能介绍,可以参考《58同城智能推荐系统的演进与实践》。在推荐系统中,我们建立多层实验,配置召回层、排序层、规则层和展示层,在各层上进行分流实验,进行不同的召回策略、排序算法、规则策略、展示样式的实验对比。
如下图所示,这里建立了包含召回层和排序层的实验。在日晷实验平台选择建立多层实验,输入实验名称,选择实验层,配置各层的算法号和分流比例即可。
实验的接入
通过在日晷前端WEB界面建立了实验后,即生成了实验唯一标识。业务方通过访问HTTP/HTTPS接口,或者RPC服务的Java接口。
日晷的架构设计
整体架构
日晷的整体架构如下:
存储层
主要包含了实验的配置数据的存储,实验日志、埋点日志等统计数据的存储。
逻辑层
日晷HTTP服务用于提供web服务,Druid是开源的实时数据处理框架,Druid服务用于处理实时埋点日志信息,Tranquility服务用于处理日志数据并将符合标准格式的数据推给Druid服务,ABTest RPC服务用于处理单层和多层实验的分流请求。
接入层
用户可在接入层配置单层或多层实验数据,查看实验不同版本的实时和历史数据指标,或者通过RPC服务接口,直接获取实验分流结果。
分流实验模型
日晷分流实验模型的设计参考了Google重叠实验框架论文《Overlapping Experiment Infrastructure: More, Better, Faster Experimentation》中的分层流量模型,结合实际的业务需求:
推荐系统的流程,包含了召回、排序的多个层次,在每个层次上都需要优化,每个层次都需要独占100%的流量。我们需要将流量复制到各层,并且保证流量正交。
多个实验应该是并行的,流量之间应该是互不干扰、相互独立的。
日晷的分流实验模型,支持单层实验和多层实验。
在单层实验上,实验独占单层的流量,不受其它实验干扰。单层实验的缺点是不能充分利用流量和业务场景多样性、层次性需求。
多层实验在横向上把实验划为多层,等于将流量在各层进行了复制,实现了流量复用,每个层次之间流量又是独立的、正交的,并且可在每层任意进行流量划分。使用多层实验即可实现一份流量,多次实验,可以在多个层次、多个维度上的进行AB测实验数据对比。
实验分流
实验的分流设计基于以下的规则:
1. 足够的均匀、随机,并且可验证
用户被分到桶内的比例应最大限度的接近流量的配置比例,例如50:50的分流配置下,用户分到两个桶内比例也应该是接近1:1。并且我们可以通过实验后台日志,验证分流的均匀性。
2. 稳定的分流结果
一个用户第一次分流被分到某个桶中,在以后的所有分流中,此用户都进入相同的桶。
日晷的分流是基于用户、实验和实验层进行的,使用均匀的散列算法,获取到HASH VALUE,将用户分配到某个桶中。在实验日志的结果验证中,可以看到分流是足够均匀的。而且分流在各个实验和层次之间是独立正交的。通过对某个用户分流结果的数百万次的验证,可以保证此用户的分流结果100%稳定。
在实验创建的时候会生成唯一的实验ID:EXPID,我们根据UID + EXPID来进行分流,这样用户在不同实验之间就是独立的,流量在实验间就是正交的。同样的,我们在实验的每层会创建唯一的层ID:LAYERID,我们根据UID + EXPID + LAYERID进行分流,就可以保证流量在实验间,在实验的每层之间都是独立、正交的。分流的流程如下图所示,最终用户会落在分流的某个桶中:
实验流程
日晷通用ABTest实验平台的流程如下:
业务方人员进入日晷系统,在WEB前端进行实验配置,选择建立单层或多层实验,根据需求配置不同版本的流量、算法。
用户请求业务方,并被分配到某个实验分流桶中。
用户产生的埋点日志,实时收集并且反馈给日晷系统,日晷的服务实时处理埋点日志,并产生实验效果数据
业务方在日晷WEB系统查看实验的A/B版本各自的实时或者离线数据效果。
实验数据统计
日晷的实验数据统计分为两个方面:
1. 离线数据分析
离线埋点数据: 基于kylin的埋点数据分析
实验日志数据:实验日志通过flume实时上传到HDFS上,每天由hadoop mr任务定时抽取到hive表中,用于验证分流是否均匀,业务线的埋点是否准确
2. 实时数据分析
实时埋点数据:基于Druid的实时数据分析。业务方通过代码埋点将日晷的分流标识放到埋点里,日晷实时收集埋点日志,通过Druid服务对数据进行实时抽取。
如图所示,日晷的实时数据展现界面:
日晷实时数据统计的技术选型对比:
利用redis数据结构来存取数据
开发简单、低延迟
多维度扩展困难
利用storm + hbase来实现
低延迟、多维度存储
维度组合庞大、扩充困难
基于 Druid 实时 OLAP 引擎实现
低延迟、低存储占用,支持多维度实时/历史数据查询
处理不及时有数据会丢失风险,不存储原始数据
Druid是面向海量数据的、用于实时查询与分析的OLAP的存储系统,提供亚秒级的多维度实时和历史数据查询。我们最终选择Druid作为日晷的实时数据处理引擎,主要是Druid提供了以下几个方面特点:
Druid提供亚秒级的查询,在我们的测试中,仅需几十毫秒即可完成一次组合维度的查询任务
不同于kylin对维度和数据进行预处理,由于Druid列式存储的方式,可以通过自定义查询进行维度的自由组合扩展,不需要进行数据预处理
提供了多种聚合查询的支持,如TopN查询,GroupBy查询,时间序列的查询等
这样我们在预先定义好了召回号、算法号、规则号、展示号的情况下,可以通过自定义查询的维度,获取不同维度下的数据统计效果。例如我们想看看在召回号recallno=20和recallno=21的情况下,排序算法号rankno=200的效果怎么样,即可在查询过滤条件中设置好召回和排序的维度值,以及聚合的类型,即可获取到结果。
日晷的实时数据处理
App端的埋点数据,通过kafka实时消费,按照埋点格式,解析为符合Druid预定义维度的数据格式,将数据通过tranquility服务发送给Druid服务,Druid服务会在预定义的时间窗口期内实时接收数据,并将数据转换为segment存储。业务方查询数据时,根据业务方在WEB界面的选择,生成包含维度、度量、聚合和过滤方法、时间窗口等的查询信息,发送给Druid获取预期的查询结果。
日晷埋点的处理流程如下:
总结
日晷通用ABTest实验平台,支持单层实验,和横向的多层的实验,通过WEB可以简单进行实验配置,提供基于Druid的实时数据分析,打通了从实验建立到实验效果评估的闭环。目前应用在58的二手车、黄页、58招聘、赶集招聘、英才、以及推荐的各个场景中,日均请求量4.5亿,一共有200+个单层和多层实验。支持了包括UI界面选取、标签文案选择、功能迭代、策略更新、算法优化等多个实验场景,为产品、技术在用户体验提升、产品特性优化、商业变现和业务的增长上提供支持和决策依据。
日晷系统的不足有以下几点,也是未来改进的方向:
日晷在纵向维度上支持还不够多样,目前仅支持进行用户维度的分流。
对于多维度的实时实验效果数据的支持还不完善。
实时数据效果查看上,用户在数据时间间隔的选择上不够灵活。